package utils;

import java.util.Arrays;

public class TargetBifurcationDiagram {
	
	//Handles the precision of images
	
	//Should probably based on the computation of something specific
	
	public double[][] bifurcationDiagram;
	
	public static int maxRes = 5; //Represents a square image of size 2^maxRes (32x32 for 5)
	
	public TargetBifurcationDiagram(double[][] bifurcationDiagram){
		this.bifurcationDiagram = bifurcationDiagram;
		if(bifurcationDiagram.length != (int) Math.pow(2, maxRes) || bifurcationDiagram[0].length != (int) Math.pow(2, maxRes)){
			System.err.println("[Warning] Size of the BifurcationDiagram "+bifurcationDiagram.length+"x"+bifurcationDiagram[0].length+" instead of the expected resolution");
		}
	}
	
	public double[][] getDiagram(int res){
		if(res > maxRes){
			System.err.println("[Warning] Resolution higher than max res. Max res used instead (1 point returned)");
			res = maxRes;
		}
		if(res == 0){
			return bifurcationDiagram;
		}
		int numberOfPoints = (int) Math.pow(2, maxRes - res);
		int startingIndex = (int) Math.pow(2, res - 1) - res%2;
		double[][] diagram = new double[numberOfPoints][numberOfPoints];
		int ind1 = 0;
		int ind2 = 0;
		for(int i = startingIndex; i<bifurcationDiagram.length; i+= (int) Math.pow(2, res)){
			for(int j = startingIndex; j<bifurcationDiagram[0].length; j+= (int) Math.pow(2, res)){
				diagram[ind1][ind2] = bifurcationDiagram[i][j];
				ind2++;
			}
			ind2 = 0;
			ind1++;
		}
		return diagram;
	}

	/**
	 * Generates a bifurcation diagram with oscillations in the center, no oscillations around
	 * @return
	 */
	public static TargetBifurcationDiagram japaneseFlag(){
		double[][] simpleTarget = new double[(int) Math.pow(2, TargetBifurcationDiagram.maxRes)][(int) Math.pow(2, TargetBifurcationDiagram.maxRes)];
		for(int i = 0; i<(int) Math.pow(2, TargetBifurcationDiagram.maxRes); i++){
			for(int j = 0; j<(int) Math.pow(2, TargetBifurcationDiagram.maxRes); j++){
				simpleTarget[i][j] = ((i-15)*(i-15)+(j-15)*(j-15) <= 25?100.0:0.0) ;//japanese flag
			}
		}
		return new TargetBifurcationDiagram(simpleTarget);
	}
	
	/**
	 * Generates a bifurcation diagram with oscillations everywhere
	 * @return
	 */
	public static TargetBifurcationDiagram flatDiagram(){
		double[][] simpleTarget = new double[(int) Math.pow(2, TargetBifurcationDiagram.maxRes)][(int) Math.pow(2, TargetBifurcationDiagram.maxRes)];
		for(int i = 0; i<(int) Math.pow(2, TargetBifurcationDiagram.maxRes); i++){
			for(int j = 0; j<(int) Math.pow(2, TargetBifurcationDiagram.maxRes); j++){
				simpleTarget[i][j] = 100.0; //flatdiagram
			}
		}
		return new TargetBifurcationDiagram(simpleTarget);
	}
	
	/**
	 * Generates a bifurcation diagram with oscillations on the left half
	 * @return
	 */
	public static TargetBifurcationDiagram twoBandsLR(){
		double[][] simpleTarget = new double[(int) Math.pow(2, TargetBifurcationDiagram.maxRes)][(int) Math.pow(2, TargetBifurcationDiagram.maxRes)];
		for(int i = 0; i<(int) Math.pow(2, TargetBifurcationDiagram.maxRes); i++){
			for(int j = 0; j<(int) Math.pow(2, TargetBifurcationDiagram.maxRes); j++){
				simpleTarget[i][j] = (j<(int) Math.pow(2, TargetBifurcationDiagram.maxRes-1)?100.0:0.0); //Oscillates on the left, nothing on the right
			}
		}
		return new TargetBifurcationDiagram(simpleTarget);
	}
	
	/**
	 * Generates a bifurcation diagram with oscillations on the right half
	 * @return
	 */
	public static TargetBifurcationDiagram twoBandsRL(){
		double[][] simpleTarget = new double[(int) Math.pow(2, TargetBifurcationDiagram.maxRes)][(int) Math.pow(2, TargetBifurcationDiagram.maxRes)];
		for(int i = 0; i<(int) Math.pow(2, TargetBifurcationDiagram.maxRes); i++){
			for(int j = 0; j<(int) Math.pow(2, TargetBifurcationDiagram.maxRes); j++){
				simpleTarget[i][j] = (j<(int) Math.pow(2, TargetBifurcationDiagram.maxRes-1)?0.0:100.0); //Oscillates on the right, nothing on the left
			}
		}
		return new TargetBifurcationDiagram(simpleTarget);
	}
	
	/**
	 * Generates a bifurcation diagram with oscillations on the upper-left half
	 * @return
	 */
	public static TargetBifurcationDiagram twoBandsUL(){
		double[][] simpleTarget = new double[(int) Math.pow(2, TargetBifurcationDiagram.maxRes)][(int) Math.pow(2, TargetBifurcationDiagram.maxRes)];
		for(int i = 0; i<(int) Math.pow(2, TargetBifurcationDiagram.maxRes); i++){
			for(int j = 0; j<(int) Math.pow(2, TargetBifurcationDiagram.maxRes); j++){
				simpleTarget[i][j] = (j+i<(int) Math.pow(2, TargetBifurcationDiagram.maxRes-1)?100.0:0.0); //Oscillates on the left, nothing on the right
			}
		}
		return new TargetBifurcationDiagram(simpleTarget);
	}
	
	/**
	 * Generates a bifurcation diagram with oscillations on the bottom right half
	 * @return
	 */
	public static TargetBifurcationDiagram twoBandsBR(){
		double[][] simpleTarget = new double[(int) Math.pow(2, TargetBifurcationDiagram.maxRes)][(int) Math.pow(2, TargetBifurcationDiagram.maxRes)];
		for(int i = 0; i<(int) Math.pow(2, TargetBifurcationDiagram.maxRes); i++){
			for(int j = 0; j<(int) Math.pow(2, TargetBifurcationDiagram.maxRes); j++){
				simpleTarget[i][j] = (j+i<(int) Math.pow(2, TargetBifurcationDiagram.maxRes)?0.0:100.0); //Oscillates on the right, nothing on the left
			}
		}
		return new TargetBifurcationDiagram(simpleTarget);
	}
	
	
	public static void main(String[] args){
		double[][] base = new double[32][32];
		for(int i=0; i<base.length; i++)
			for(int j=0; j<base[0].length; j++)
				base[i][j] = i+j;
		TargetBifurcationDiagram dia = new TargetBifurcationDiagram(base);
		System.out.println("Base's size: "+base.length+"x"+base[0].length);
		double[][] target = dia.getDiagram(5);
		System.out.println("Target's size: "+target.length+"x"+target[0].length);
	}
	
}
